package com.common.utils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;

import jxl.Sheet;
import jxl.Workbook;
import jxl.biff.DisplayFormat;
import jxl.format.Alignment;
import jxl.format.Border;
import jxl.format.BorderLineStyle;
import jxl.format.Colour;
import jxl.format.UnderlineStyle;
import jxl.read.biff.BiffException;
import jxl.write.Label;
import jxl.write.Number;
import jxl.write.NumberFormats;
import jxl.write.WritableCellFormat;
import jxl.write.WritableFont;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
import jxl.write.WriteException;
import jxl.write.biff.RowsExceededException;


/**
 * @author 马智城
 * 功能说明: 生成Excel
 * Sep 23, 2012 2:19:42 PM
 */
public class WriteExcelTemplate {
	public WritableWorkbook wwb = null;
	//文字位置
	public Alignment[] alignments;
	//边框位置
	public Border[] borders;
	//边框样式
	public BorderLineStyle[] borderLineStyles;
	
	//标题 字体
	public WritableFont title_default;
	public String title_fontName ="黑体";
	public int title_fontSize =14;
	//加粗
	public boolean tille_isBold = true;
	//倾斜
	public boolean tille_isItalic = false;
	//底线
	public boolean title_hsaUnderLine = false;
	public Colour title_Color = Colour.BLACK;
	
	//数据 字体
	public WritableFont data_default;
	public String data_fontName ="宋体";
	public int data_fontSize = 12;
	public boolean data_isBold = false;
	public boolean data_isItalic = false;
	public boolean data_hsaUnderLine = false;
	public Colour data_Color = Colour.BLACK;
	
	//背景颜色
	public Colour bg_color;
	
	//默认 字体类型
	public String fontType;
	//单元格数据类型
	public DisplayFormat dataType;
	
	{
		title_default = new WritableFont(
				WritableFont.createFont(title_fontName),
				title_fontSize,
				tille_isBold?WritableFont.BOLD:WritableFont.NO_BOLD,
				tille_isItalic,
				title_hsaUnderLine?UnderlineStyle.SINGLE:UnderlineStyle.NO_UNDERLINE,
				title_Color
				);
		data_default = new WritableFont(
				WritableFont.createFont(data_fontName),
				data_fontSize,
				data_isBold?WritableFont.BOLD:WritableFont.NO_BOLD,
				data_isItalic,
				data_hsaUnderLine?UnderlineStyle.SINGLE:UnderlineStyle.NO_UNDERLINE,
				data_Color
				);
		
		fontType = "data";
		bg_color = Colour.WHITE;
		dataType = NumberFormats.TEXT;
		
		alignments =new  Alignment[]{
				Alignment.CENTRE,	//居中
				Alignment.FILL,		//填充，当数据宽度小于单元格时，自动重复填充数据
				Alignment.GENERAL,	//常规，当数据长度大于单元格长度时，数据显示超出单元格
				Alignment.JUSTIFY,	//自动调整，当数据长度对于单元格宽度时，自动换行
				Alignment.LEFT,		//居左
				Alignment.RIGHT		//居右
				};
		borders = new Border[]{
				Border.ALL, 	//全框
				Border.NONE, 	//无框
				Border.TOP,		//上
				Border.RIGHT, 	//右
				Border.BOTTOM, 	//下
				Border.LEFT 	//左
				};
		borderLineStyles = new BorderLineStyle[]{
				BorderLineStyle.NONE,		//无
				BorderLineStyle.THIN,		//细线
				BorderLineStyle.THICK,		//粗线
				BorderLineStyle.DASH_DOT,		//破折点 (横点横)
				BorderLineStyle.DASH_DOT_DOT,	//破折点点 (横店点横)
				BorderLineStyle.DASHED,		
				BorderLineStyle.DOTTED,			
				BorderLineStyle.DOUBLE,
				BorderLineStyle.HAIR,
				BorderLineStyle.MEDIUM,
				BorderLineStyle.MEDIUM_DASH_DOT,
				BorderLineStyle.MEDIUM_DASH_DOT_DOT,
				BorderLineStyle.MEDIUM_DASHED,
				BorderLineStyle.SLANTED_DASH_DOT
				};
	}
	
	/*--------------------------构造方法----------------------------*/
	protected WriteExcelTemplate() {} 
	
	protected WriteExcelTemplate(String fileUrl){
		wwb = createNewExcel(fileUrl);
	}
	
	protected WriteExcelTemplate(ByteArrayOutputStream bos,File file){
		wwb = readOldTemplte(bos,file);
	}

	protected WriteExcelTemplate(String fileUrl,String sheetName){
		wwb = createNewExcel(fileUrl,"sheet",0);
	}
	
	/*--------------------------获得实例---------------------------*/
	public static WriteExcelTemplate getInstance(){
		return new WriteExcelTemplate();
	}
	
	public static WriteExcelTemplate getInstance(ByteArrayOutputStream bos,File file){
		return new WriteExcelTemplate(bos,file);
	}
	
	public static WriteExcelTemplate getInstance(String fileUrl){
		return new WriteExcelTemplate(fileUrl);
	}
	
	public static WriteExcelTemplate getInstance(String fileUrl,String sheetName){
		return new WriteExcelTemplate(fileUrl,sheetName);
	}
	
	/*--------------------------常用方法---------------------------*/
	/**
	 * 方法名:readOldTemplte
	 * 方法作用:通过原有模版文件 生成新的导出文件
	 * @param bos	输出流
	 * @param file	原有模板文件
	 * @return	可操作工作簿对象
	 */
	private WritableWorkbook readOldTemplte(ByteArrayOutputStream bos,File file) {
		Workbook wb = null;
		try {
			wwb = wb.createWorkbook(bos, wb.getWorkbook(file));
		} catch (BiffException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return wwb;
	}
	
	/**
	 * 方法名:createNewExcel
	 * @see 方法作用:新建一个 Excel 文件
	 * @param fileUrl	新建文件路径及文件名
	 * @return 可操作工作簿对象
	 */
	private WritableWorkbook createNewExcel(String fileUrl) {
		File file = null;
		WritableWorkbook wwb = null;
		try {
			file = FileUtil.createNewFile(fileUrl);
			wwb = Workbook.createWorkbook(file);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return wwb;
	}
	
	/**
	 * 方法名:createNewExcel
	 * @see 方法作用:新建一个 Excel 文件
	 * @param fileUrl	新建文件路径及文件名
	 * @param sheetName 工作表名称
	 * @param location 工作表所在位置
	 * @return 可操作工作簿对象
	 */
	public WritableWorkbook createNewExcel(String fileUrl,String sheetName,int location){
		File file = null;
		try {
			file = FileUtil.createNewFile(fileUrl);
			wwb = Workbook.createWorkbook(file);
			wwb.createSheet(sheetName, location);
		} catch (IOException e) {
			e.printStackTrace();
		} 
		return wwb ;
	}
	
	/**
	 * 方法名:createSheet
	 * @see 方法作用:创建一个 工作表
	 * @param sheetName 工作表名称
	 * @param location 工作表下标
	 * @return 新创建工作表
	 */
	public WritableSheet createSheet(String sheetName, int location) {
		return wwb.createSheet(sheetName, location);
	}
	
	/**
	 * 方法名:createSheets
	 * @see 方法作用:批量创建工作表
	 * @param sheetsName 工作表名称数组
	 * @param insertIndex 插入起始位置位置
	 * @return 新创建的工作表集合
	 */
	public WritableSheet[] createSheets(String[] sheetsName,int insertIndex){
		WritableSheet[] wss = new WritableSheet[sheetsName.length];
		for (int i = 0; i < wss.length; i++) {
			String name = sheetsName[i]==null||sheetsName[i].equals("")?" ":sheetsName[i];
			wss[i] = wwb.createSheet(name, insertIndex+i);
		}
		return wss;
	}

	/**
	 * 方法名:addData
	 * @see 方法作用:填充数据
	 * @param sheet 	欲填充数据的单元格
	 * @param data  	数据
	 * @param r_Num		行数(从0起始)
	 * @param c_Num		列数(从0起始)
	 */
	public void addData(Object sheet,String data,int r_Num,int c_Num){
		try {
			Label label = new Label(c_Num,r_Num,data,cellFormat(2));
			tranSheet(sheet).addCell(label);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 方法名:addData
	 * @see 方法作用:填充数据
	 * @param sheet 	欲填充数据的单元格
	 * @param data  	数据
	 * @param r_Num		行数(从0起始)
	 * @param c_Num		列数(从0起始)
	 * @param align		数据位置(0-居中，1-填充，2-常规，3-自动调整，4-居左，5-居右)
	 */
	public void addData (Object sheet,String data,int r_Num,int c_Num,int align){
		try {
			Label label = new Label(c_Num,r_Num,data,cellFormat(align));
			tranSheet(sheet).addCell(label);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 方法名:addData
	 * @see 方法作用:填充数据，无边框无样式
	 * @param sheet 	欲填充数据的单元格
	 * @param data  	数据
	 * @param r_Num		行数(从0起始)
	 * @param c_Num		列数(从0起始)
	 * @param align		数据位置(0-居中，1-填充，2-常规，3-自动调整，4-居左，5-居右)
	 * @param border	边框位置(0-全框，1-无框，2-上，3-右，4-下，5-左)
	 */
	public void addDataNoBorderNoStyle (Object sheet,String data,int r_Num,int c_Num,int align,int border){
		try {
			Label label = new Label(c_Num,r_Num,data,cellFormat(align,1,0));
			tranSheet(sheet).addCell(label);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 方法名:addData
	 * @see 方法作用:填充数据，自定义边框样式
	 * @param sheet 	欲填充数据的单元格
	 * @param data  	数据
	 * @param r_Num		行数(从0起始)
	 * @param c_Num		列数(从0起始)
	 * @param align		数据位置(0-居中，1-填充，2-常规，3-自动调整，4-居左，5-居右)
	 * @param border	边框位置(0-全框，1-无框，2-上，3-右，4-下，5-左)
	 * @param borderStyle	边框样式 (0-无，1-细线，2-粗线......)
	 */
	public void addData (Object sheet,String data,int r_Num,int c_Num,int align,int border,int borderStyle){
		try {
			Label label = new Label(c_Num,r_Num,data,cellFormat(align,border,borderStyle));
			tranSheet(sheet).addCell(label);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 方法名:addNumberData
	 * @see 方法作用:填充数据，自定义边框样式
	 * @param sheet 	欲填充数据的单元格
	 * @param data  	数据
	 * @param r_Num		行数(从0起始)
	 * @param c_Num		列数(从0起始)
	 * @param align		数据位置(0-居中，1-填充，2-常规，3-自动调整，4-居左，5-居右)
	 * @param border	边框位置(0-全框，1-无框，2-上，3-右，4-下，5-左)
	 * @param borderStyle	边框样式 (0-无，1-细线，2-粗线......)
	 */
	public void addNumberData (Object sheet,String data,int r_Num,int c_Num,int align,int border,int borderStyle){
		try {
			Number number = new Number(c_Num, r_Num, Double.valueOf(data),  cellFormat(align,border,borderStyle));
			tranSheet(sheet).addCell(number);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 方法名:mergeCells
	 * @see 方法作用:合并单元格
	 * @param tlr	左上角单元格行数 top left row		
	 * @param tlc	左上角单元格列数 top left column 	
	 * @param brr	右下角单元格行数 bottom right row	
	 * @param brc	右下角单元格列数 bottom right column	
	 */
	public void mergeCells(Object sheet,int tlr,int tlc,int brr,int brc){
		try {
			tranSheet(sheet).mergeCells(tlc, tlr, brc, brr);
		} catch (RowsExceededException e) {
			e.printStackTrace();
		} catch (WriteException e) {
			e.printStackTrace();
		}
	}
	
	
	public WritableCellFormat cellFormat(int align) throws Exception{
		if(align > alignments.length+1) throw new Exception("齐方式指定错误");
		WritableCellFormat wfc = new WritableCellFormat(dataType);
		wfc.setAlignment(alignments[align]);
		wfc.setBorder(borders[0], borderLineStyles[0]);
		wfc.setFont(fontType.equals("data")?data_default:title_default);
		wfc.setBackground(bg_color);
		return wfc;
	}
	
	public WritableCellFormat cellFormat(int align,int border,int borderStyle) throws Exception{
		if(align > alignments.length+1) throw new Exception("对齐方式指定错误");
		if(border > borders.length+1) throw new Exception("边框位置指定错误");
		if(borderStyle > borderLineStyles.length+1) throw new Exception("边框样式指定错误");
		
		WritableCellFormat wfc = new WritableCellFormat(dataType);
		
		if(dataType instanceof Number){
			//如果是数组 应该可以设置格式化内容
		}
		
		wfc.setAlignment(alignments[align]);
		wfc.setBorder(borders[border], borderLineStyles[borderStyle]);
		wfc.setFont(fontType.equals("data")?data_default:title_default);
		wfc.setBackground(bg_color);
		return wfc;
	}
	
	/**
	 * 方法名:setColumnWidth
	 * @see 方法作用:设置列宽
	 * @param sheet		当前工作表
	 * @param colNum	列数
	 * @param width		列宽
	 */
	public void setColumnWidth(Object sheet,int colNum,int width){
		tranSheet(sheet).setColumnView(colNum,width);
	}
	
	/**
	 * 方法名:setColumnsWidth
	 * @see 方法作用:设置多列 列宽
	 * @param sheet		当前工作表
	 * @param colNum	起始列数
	 * @param widths	列宽 集合
	 */
	public void setColumnsWidth(Object sheet,int colNum,int[] widths){
		for(int width :widths){
			tranSheet(sheet).setColumnView(colNum++,width);
		}
	}
	
	/**
	 * 方法名:setRowHeight
	 * @see 方法作用:	设置行高
	 * @param sheet		当前工作表
	 * @param rowNum	行数
	 * @param height	行高
	 */
	public void setRowHeight(Object sheet, int rowNum, int height){
		try {
			tranSheet(sheet).setRowView(rowNum,height);
		} catch (RowsExceededException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 方法名:setRowsHeight
	 * @see 方法作用:	设置多行行高
	 * @param sheet		当前工作表
	 * @param rowNum	起始行数
	 * @param heights	行高 集合
	 */
	public void setRowsHeight(Object sheet, int rowNum, int[] heights){
		for(int height : heights){
			try {
				tranSheet(sheet).setRowView(rowNum++,height);
			} catch (RowsExceededException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 方法名:tranSheet
	 * @see 方法作用:转型
	 * @param sheet	
	 * @return	WritableSheet 类型 工作表
	 */
	public WritableSheet tranSheet(Object sheet){
		if(sheet instanceof Sheet || sheet instanceof WritableSheet) return (WritableSheet) sheet;
		else{
			 try {
				throw new Exception("转型异常");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return null;
	}
	
	/**
	 * 方法名:colseWorkBook
	 * @see 方法作用:将内存中的数据写入到文件中
	 */
	public void colseWorkBook(){
		try {
			wwb.write();
			wwb.close();
		} catch (IOException e) {
			System.out.println("写入错误");
			e.printStackTrace();
		} catch (WriteException e) {
			System.out.println("关闭错误");
			e.printStackTrace();
		}
	}
	
}
